// -*- c-basic-offset: 2 default-tab-width: 2 indent-tabs-mode: t -*-
// vim: autoindent tabstop=2 noexpandtab shiftwidth=2 softtabstop=2
//===------------ Closure.cpp
//
//             This file is part of the reactor project
//                Author: R-Core Team
//
//===---------------------------------------------------------------------===//

#include "Promise.h"
#include "Const.h"
#include "Closure.h"
#include "RModule.h"
#include "Bindings.h"

using namespace R;
namespace R{
struct pattern_t *build_pattern(int total, ConstPool *cpool, struct cpool_vector patterns);
};

Closure* Closure::doNew(FunInfo *fun, Environment* env){
	R_VAR(Closure *, res);
  R_PARAM(env);
  res = static_cast<Closure*>(Closure::operator new(sizeof(Closure), virtualVT));
  res->fun = fun;
  res->env = env;
	return res;
}

void FunInfo::makeFormals(cpool_entry *params, cpool_entry *cpool_orig){
  R_VAR(Promise*, prom);
  R_VAR(Any*, name);
	ConstPool* cpool = &module->cpool;
	FunInfo* finfos = module->funInfos;

	hasDot = false;

  Assert(params->type == CPOOL_INTSXP,
      "Parameters of a Closure must be an Int");
  Assert(params->data.pe_int.names > 0,
      "Parameters positions need to have names");

  int len = params->data.pe_int.size;
  struct cpool_vector promises_name_pe = module->cpool_orig[params->data.pe_int.names].data.pe_vector;
  Assert(len == promises_name_pe.size,
      "Parameters names must have same length than address");

  bindings = Bindings::create(len, len);
#ifndef R_EXACT_KEYWORDS
	dstruct = build_pattern(len, cpool, promises_name_pe);
#endif

  for(int i = 0; i < len; i++){ // TODO we only need a number, so need to have Parametrized Frames
		if((*cpool)[promises_name_pe.values[i]] == SymbolTable::threeDots){
			rerror_on(hasDot, "function has many times '...'");
			hasDot = true;
		}// else {
			prom = Promise::doNew(&finfos[params->data.pe_int.values[i]], 0);
			name = (*cpool)[promises_name_pe.values[i]];
			Assert(Any::isOfType<Symbol>(name), "Name must be a symbol");
			bindings->set(i, static_cast<Symbol*>(name), prom);
		//}
  }
}

Any* FunInfo::getVar(Symbol *sym, bool* has){
	int idx;
	R_VAR(Any *, tmp);
	R_PARAM(sym);

	if((idx = bindings->resolve(sym)) >= 0) {
		*has = 1;
		return bindings->get(idx);
	} else
		return NULL;
}
